package net.protocol.diameter.avp;

import net.protocol.common.util.Bits;
import net.protocol.common.util.NtpTime;

import java.nio.ByteBuffer;
import java.util.Date;

/**
 * <pre>
 *    Time
 *       The Time format is derived from the OctetString AVP Base Format.
 *       The string MUST contain four octets, in the same format as the
 *       first four bytes are in the NTP timestamp format.  The NTP
 *       Timestamp format is defined in chapter 3 of [SNTP].
 * 
 *       This represents the number of seconds since 0h on 1 January 1900
 *       with respect to the Coordinated Universal Time (UTC).
 * 
 *       On 6h 28m 16s UTC, 7 February 2036 the time value will overflow.
 *       SNTP [SNTP] describes a procedure to extend the time to 2104.
 *       This procedure MUST be supported by all DIAMETER nodes.
 * </pre>
 * 
 * @author jinhongw@gmail.com
 * @see java.util.Date
 * @see <a href="http://tools.ietf.org/html/rfc1305">Network Time Protocol</a>
 * @see <a href="http://datatracker.ietf.org/doc/rfc2030/">Simple Network Time Protocol</a>
 */
public class Time extends AbstractAVP<Long> {
    public final static int DATA_LENGTH = 4;
	  
    private final long data;
	
    /**
     * @param code     AVP Code
     * @param date     Java standard Date
     */
	public Time(int code, Date date) {
		this(code, DEFAULT_VENDOR_ID, date);
	}

    /**
     * @param code     AVP Code
     * @param vendorId Vendor-ID
     * @param date     Java standard Date
     */
	public Time(int code, int vendorId, Date date) {
		this(code, vendorId, NtpTime.toNtpTime(date.getTime()));
	}
	
    /**
     * @param code     AVP Code
     * @param ntpTime  NTP timestamp
     */
	public Time(int code, long ntpTime) {
	     super(code, DATA_LENGTH);

	     this.data = ntpTime;
	}

    /**
     * @param code     AVP Code
     * @param vendorId Vendor-ID
     * @param ntpTime  NTP timestamp
     */
	public Time(int code, int vendorId, long ntpTime) {
	     super(code, vendorId, DATA_LENGTH);

	     this.data = ntpTime;
	}

    /**
     * Creates a new <code>Time</code> with the given DiameterAVPHeader and source ByteBuffer
     *
     * @param header Diameter AVP Header
     * @param src The buffer from which bytes are to be retrieved
     */
    Time(DiameterAVPHeader header, ByteBuffer src) {
        super(header, src);

        this.data = Bits.get32(src);
    }

	@Override
	public ByteBuffer byteMe(ByteBuffer dst) {
		super.byteMe(dst);
		
	    Bits.put32(dst, data);
	    
	    return dst;
	}
    
    @Override
    public Long getData() {
        return data;
    }
    
    @Override
    public byte[] getDataBytes() {
    	return Bits.toByteArray32(data);
    }

    @Override
    public final boolean isGroup() {
        return false;
    }
    
	@Override
	public DataFormat getType() {
		return DataFormat.Time;
	}

	@Override
	public String getName() {
		return DataFormat.Time.name();
	}

	@Override
	protected void detail(StringBuilder buf) {
		buf.append(new NtpTime(data));
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		Time other = (Time) obj;
		if (data != other.data)
			return false;
		return true;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + (int) (data ^ (data >>> 32));
		return result;
	}
}
